-----------------------------------------
-- PROJET 06-07 - micro java : grammaire LL(3)
-- au format EGG
------------------------------------------
-- La tds des classes (avec tds des methodes et des constructeurs compris)
-- un heritage "recursif" pour les sous-classes
inh tdc : TDS<CLASSE> for CLASSES, DEFCLASSE, DEFS, DEF, BLOC, INSTS, INST,
			SIX, TYPE, PARF, PARFS, PARFSX, F, TX, T, ESX, E,
			ES, ER, AFFX, ERX, ARGS, ARGSX, Q;
-- La tds des variables (attributs + locales)
-- heritage "recursif" a chaque BLOC
inh tds : TDS<ATT_PARAM> for DEFS, DEF, BLOC, INSTS, INST, SIX,
	 F, TX, T, ESX, ES, ER, AFFX, E, ERX, ARGS, ARGSX, Q;
-- Le deplacement des locales

-- La tds des parametres
inh tdp : TDS<ATT_PARAM> for PARFS, PARF, PARFSX;
inh args : List<DTYPE> for ARGS, ARGSX;
-- 
inh classe : CLASSE for DEFS, DEF, BLOC, INSTS, INST, SIX,
	F, TX, T, ESX, ES, ER, AFFX, E, ERX, ARGS, ARGSX, Q;
syn classedef : CLASSE for DEFCLASSE;
inh classe_englobante : CLASSE for DEFCLASSE;
inh methode : METHODE for BLOC, INSTS, INST, SIX, E, ER, AFFX, ES, ERX, T, ESX, F, TX, Q, ARGS, ARGSX;

--  Les types
syn type : DTYPE for TYPE, AFFX, F, T, TX, E, ER, ERX, ES, ESX, OPREL, OPADD, OPMUL, OPUN, Q;
inh prev_type : DTYPE for TX, AFFX, ERX, ESX, Q;
inh ident : String for Q;

-- syn params : TDS<ATT_PARAM> for Q;
-- Le type d'argument d'un opÃ©rateur (nil si quelconque)
-- Les opÃ©rateurs binaires ont tous des types Ã  droite et Ã  gauche.
-- compatibles (mÃªme si arg_type=nil)
-- (Ils pourraient Ãªtre diffÃ©rents avec arg_type1 et arg_type_2)
syn arg_type : DTYPE for OPREL, OPADD, OPMUL, OPUN;

syn herite_de : String for EXTENSION;
syn numdefqual : int for DEFQUAL; -- remonter la visibilitÃ©
inh numdef : int for DEF; -- redescendre la visibilitÃ©

inh depl_att : int for DEF, DEFS;
inh depl_meth : int for DEF, DEFS;
inh empl_param : int for PARF,PARFSX;

-- le deplacement de l'objet dÃ©fini dans DEF
syn def_depl : int for DEF;
syn type_def : int for DEF; --remontons Ã  DEFS le type de DEF
	-- 0 pour les attributs
	-- 1 pour les constructeurs
	-- 2 pour les procÃ©dures
	-- 3 pour les fonctions
	-- 4 pour les classes internes...
-- deplacement dans les BLOC pour les variables local
inh depl_base : int for BLOC, INSTS, INST, SIX ;
inh depl_bloc : int for BLOC, INSTS, INST, SIX ;
syn new_depl : int for INST ;
--syn type_ident : String for Q;

-- le numero d'une classe 
inh num_classe : int for CLASSES, DEFCLASSE;
syn next_num_classe : int for DEFCLASSE;

-- la machine pour laquelle on va generer du code
inh machine : TAM for CLASSES, DEFCLASSE, DEFS, DEF, BLOC, INSTS, INST,
			SIX, TYPE, PARF, PARFS, PARFSX, F, TX, T, ESX, E,
			ES, ER, AFFX, ERX, ARGS, ARGSX, Q, OPREL, OPUN, OPADD, OPMUL ;
syn code : String for CLASSES, DEFCLASSE, DEF, DEFS, BLOC, INSTS, INST, AFFX, E, SIX,
		      ER, OPREL, OPADD, OPMUL, F, OPUN, ESX, T, ES, ERX, TX, Q,ARGS,ARGSX;
inh hcode : String for Q;

--
syn estValeur : boolean for F, ER, ES, T, Q; 
inh hCodeEstValeur : boolean for Q; 

-- Affectabilit? d'une expression
-- inh isAffectable : boolean for E, ER, ES, ESX, ERX, T, F, TX, Q; 

-- les terminaux 
space separateur is  "[\r\n\t ]+";
space comm is  "\/\/[^\n]*\n";
sugar paro is  "\(";
sugar parf is  "\)";
sugar aco is  "\{";
sugar acf is  "\}";
sugar cro is  "\[";
sugar crf is  "\]";
sugar virg is  ",";
sugar pv is  "\;";
sugar pt is  "\.";
sugar affect is  "=";
sugar si is  "if";
sugar sinon is  "else";
sugar tantque is  "while";
sugar void is  "void";
sugar int is  "int";
sugar bool is  "boolean";
sugar classe is  "class";
sugar etend is  "extends";
sugar retour is  "return";
sugar nouveau is  "new";
sugar public is  "public";
sugar prive is  "private";
sugar nil is  "null";
sugar inf is  "\<";
sugar infeg is  "\<=";
sugar sup is  "\>";
sugar supeg is  "\>=";
sugar eg is  "==";
sugar neg is  "\!=";
sugar plus is  "\+";
sugar moins is  "\-";
sugar ou is  "\|\|";
sugar mult is  "\*";
sugar div is  "\/";
sugar mod is  "\%" ; 
sugar et is  "\&\&";
sugar non is  "\!";
sugar vrai is  "true";
sugar faux is  "false";
term entier is  "[0-9]+";
term ident is  "[_A-Za-z][_0-9A-Za-z]*";

---------- REGLES DE PRODUCTION ----------------------------------------
PROGRAMME -> #init CLASSES #fin ;
	global tdc : TDS<CLASSE>;
	       machine : TAM;
#init {
do 
 	tdc := new TDS<CLASSE>();
    	machine := new TAM("output");
	CLASSES^machine := machine;
	CLASSES^tdc := tdc;
	CLASSES^num_classe := 0;
end
}

#fin {
	local code : String;
do
	write tdc.toString();
	code := machine.genProlog(tdc) + CLASSES^code;
	call machine.writeFile(code);
end
}

CLASSES -> #code;
#code{
do
	CLASSES^code := "";
end
}


CLASSES -> #transtds DEFCLASSE #transnum_classes CLASSES #code;
#transtds{
do
	DEFCLASSE^classe_englobante := nil;
end
}

#transnum_classes{
do
	CLASSES1^num_classe := DEFCLASSE^next_num_classe;
end
}

#code{
do
	CLASSES^code := DEFCLASSE^code + CLASSES1^code;
end
}


-- definition d'une classe
DEFCLASSE -> classe ident EXTENSION aco #transtds DEFS acf #code;
global 	classe_def : CLASSE;

#transtds {
local
	classe_parente : CLASSE;
do
	if(EXTENSION^herite_de = nil) then
		classe_parente := nil;
	else
		classe_parente := DEFCLASSE^tdc.chercherGlobalement(EXTENSION^herite_de);
		-- Verification de l'existence de la classe etendue
		if(classe_parente = nil) then
			error(T_03,EXTENSION^herite_de);
		end
	end
	if (DEFCLASSE^classe_englobante = nil) then
		classe_def := new CLASSE(ident^txt, DEFCLASSE^tdc, classe_parente, DEFCLASSE^num_classe);
	else
		classe_def := new CLASSE(ident^txt, DEFCLASSE^classe_englobante, classe_parente, DEFCLASSE^num_classe);
	end
	DEFS^classe := classe_def;
	DEFCLASSE^classedef :=classe_def;
	DEFS^tds := classe_def.getAttributs();
	DEFS^tdc := classe_def.getSsClasses();
	call DEFCLASSE^tdc.inserer(ident^txt,classe_def);
	DEFCLASSE^next_num_classe := DEFCLASSE^num_classe + 1; --pour renvoyer un cran au dessus les numeros de classes
	if(classe_parente=nil) then
		DEFS^depl_meth := 0; --XXX on commence a 0, on peut changer..
		DEFS^depl_att := 1; --XXX on commence a 1, on peut changer..
	else
		DEFS^depl_meth := classe_parente.getMaxMethNum()+1;
		DEFS^depl_att := classe_parente.getMaxAttNum()+1;
	end
end
}

#code {
do
	DEFCLASSE^code := DEFCLASSE^machine.genConstrByDefault(classe_def) + DEFS^code;
end
}

-- heritage
EXTENSION -> etend ident #heritage ;
#heritage{
do
	EXTENSION^herite_de := ident^txt;
end
}
	
EXTENSION ->  #heritage ;
#heritage{
do
	EXTENSION^herite_de := nil;
end
}

-- les attributs et mÃ©thodes
DEFS ->   #code;
#code {
do
	DEFS^code :="";
end
}

DEFS ->  DEFQUAL #visibilite DEF #depl DEFS #code;
#visibilite{
do
	DEF^numdef := DEFQUAL^numdefqual;
end
}
#depl{
do
	if (DEF^type_def = 0) then -- attribut
		DEFS1^depl_att := DEF^def_depl;
		DEFS1^depl_meth := DEFS^depl_meth;
	elseif(DEF^type_def = 2 | DEF^type_def = 3) then -- mÃ©thode
		DEFS1^depl_meth := DEF^def_depl;
		DEFS1^depl_att := DEFS^depl_att;
	else	
		DEFS1^depl_meth := DEFS^depl_meth;
		DEFS1^depl_att := DEFS^depl_att;
	end
end
}

#code {
do
	DEFS^code := DEF^code + DEFS1^code;
end
}

-- public, private
DEFQUAL -> public #numero;
#numero {
do
	DEFQUAL^numdefqual := 1;
end
}

DEFQUAL -> prive #numero;
#numero {
do
	DEFQUAL^numdefqual := 1;
end
}

-- attribut
DEF -> #type_def TYPE ident pv #addattribut  ;
#type_def{
do
	DEF^type_def := 0;
	DEF^code := ""; --Pas de code généré pour un attribut
end
}
#addattribut {
	local att : ATT_PARAM;
do
	att := new ATT_PARAM(TYPE^type,DEF^depl_att,new VISIBILITE(DEF^numdef),"SB",0);
	call DEF^tds.inserer(ident^txt,att);
	DEF^def_depl := DEF^depl_att+1;

end
}

-- methode (fonction)
DEF -> #type_def TYPE ident paro #creer_tdp PARFS parf #creer_methode BLOC #fin;
global  ma_tdp : TDS<ATT_PARAM>;
	meth : METHODE;

#type_def{
do
	DEF^type_def := 3;
end
}
#creer_tdp{
do
	ma_tdp := new TDS<ATT_PARAM>(DEF^tds);
	PARFS^tdp := ma_tdp;
end
}
#creer_methode{
local 	meths : Collection<METHODE>;
      	depl : int;
	methParente : METHODE;
	ma_tds : TDS<ATT_PARAM> ;
	sign : List<ATT_PARAM>;
do
	meths := DEF^classe.getMethodes();
  	depl := DEF^depl_meth;
	meth:=DEF^classe.getMethodeStricte(ident^txt,ma_tdp,false);
	if (~(meth = nil)) then --La methode a deja ete definie localement
		error(T_08,ident^txt+meth.getStringSignature());
	end
	if(DEF^classe.getParente() = nil) then
		DEF^def_depl := depl+1;
  	else
   		methParente := DEF^classe.getMethodeStricte(ident^txt,ma_tdp,true);
   		if(methParente=nil) then
    			-- la methode n'existait pas dans les parentes
			DEF^def_depl := depl+1;
   		else
   			-- la methode existait dans les parentes
			DEF^def_depl := depl;
    			depl := methParente.getNumero();
			call meths.remove(methParente);
   		end
  	end
	meth := new METHODE(TYPE^type, new VISIBILITE(DEF^numdef),ma_tdp , DEF^classe.getName(), depl, ident^txt);
	call meths.add(meth);
	
	ma_tds := new TDS<ATT_PARAM>(ma_tdp);
	sign := meth.getSignature();
	call ma_tds.inserer("this", new ATT_PARAM(DEF^classe, (0-sign.size()), new VISIBILITE(-1), "LB", 2));
	BLOC^tds := ma_tds;

	-- init du depl du bloc
	BLOC^depl_base := 0;  --XXX ou 1 ???
	BLOC^depl_bloc := 0;
	BLOC^methode := meth;
	
	write("----------- debut "+ident^txt+" -------------\n");
end
}
#fin{
do
	DEF^code := DEF^machine.genDefMethode(meth,BLOC^code);
	write("------------ fin "+ident^txt+" --------------\n");
end
}


-- methode (procedure)
DEF -> #type_def void ident  paro #creer_tdp PARFS parf #creer_methode BLOC #fin ;

global ma_tdp : TDS<ATT_PARAM>;
       meth : METHODE;

#type_def{
do
	DEF^type_def := 2;
end
}
#creer_tdp{
do
	ma_tdp := new TDS<ATT_PARAM>(DEF^tds);
	PARFS^tdp := ma_tdp;
end
}
#creer_methode{
local 	depl : int;
	meths : Collection<METHODE>;
	methParente : METHODE;
	ma_tds : TDS<ATT_PARAM> ;
	sign : List<ATT_PARAM>;
do
	meths := DEF^classe.getMethodes();
  	depl := DEF^depl_meth;
	meth:=DEF^classe.getMethodeStricte(ident^txt,ma_tdp,false);
	if (~(meth = nil)) then --La methode a deja ete definie localement
		error(T_08,ident^txt);
	end
	if(DEF^classe.getParente() = nil) then
		DEF^def_depl := depl+1;
  	else
   		methParente := DEF^classe.getMethodeStricte(ident^txt,ma_tdp,true);
   		if(methParente=nil) then
    			-- la methode n'existait pas dans les parentes
			DEF^def_depl := depl+1;
   		else
   			-- la methode existait dans les parentes
			DEF^def_depl := depl;
    			depl := methParente.getNumero();
			call meths.remove(methParente);
   		end
  	end
	meth := new METHODE(new PTYPE("void",0), new VISIBILITE(DEF^numdef), ma_tdp, DEF^classe.getName(), depl, ident^txt);
	call meths.add(meth);

	ma_tds := new TDS<ATT_PARAM>(ma_tdp);
	sign := meth.getSignature();
	call ma_tds.inserer("this", new ATT_PARAM(DEF^classe, (0-sign.size()), new VISIBILITE(-1), "LB", 2));
	BLOC^tds := ma_tds;
	
	-- init du depl du bloc
	BLOC^depl_base := 0;  --XXX ou 1 ???
	BLOC^depl_bloc := 0;
	BLOC^methode := meth;

	write("----------- debut "+ident^txt+" -------------\n");
end
}
#fin{
do
	DEF^code := DEF^machine.genDefMethode(meth,BLOC^code);
	write("------------ fin "+ident^txt+" --------------\n");
end
}

-- constructeur
DEF -> #type_def ident paro #creer_tdp PARFS parf #creer_constructeur BLOC #fin ; 
global ma_tdp : TDS<ATT_PARAM>;
       constr : CONSTRUCTEUR;

#type_def{
do
	DEF^type_def := 1;
end
}
#creer_tdp{
do
	ma_tdp := new TDS<ATT_PARAM>(DEF^tds);
	PARFS^tdp := ma_tdp;
end
}
#creer_constructeur{
local 
	cons : Collection<CONSTRUCTEUR>;
	ma_tds : TDS<ATT_PARAM> ;
	sign : List<ATT_PARAM>;
do
	constr := DEF^classe.getConstructeurStrict(ma_tdp);
	if(~(constr = nil | constr.estDefaut())) then
		error(T_10,ident^txt+constr.getStringSignature());
	end
	constr := new CONSTRUCTEUR(new VISIBILITE(DEF^numdef), ma_tdp);
	cons := DEF^classe.getConstructeurs();
	call cons.add(constr);
	DEF^def_depl := 0; -- inutile
	
	ma_tds := new TDS<ATT_PARAM>(ma_tdp);
	sign := constr.getSignature();
	call ma_tds.inserer("this", new ATT_PARAM(DEF^classe, (0-sign.size()), new VISIBILITE(-1), "LB", 2));
	BLOC^tds := ma_tds;
	
	-- init du depl du bloc
	BLOC^depl_base := 0;  --XXX ou 1 ???
	BLOC^depl_bloc := 0;
	BLOC^methode := nil;

	write("----------- debut "+ident^txt+" -------------\n");
end
}
#fin{
do
	DEF^code := DEF^machine.genConstructeur(constr,DEF^classe,BLOC^code);
	write("------------ fin "+ident^txt+" --------------\n");
end
}

-- classe interne
DEF -> #type_def #defclasse DEFCLASSE #fin;
#type_def{
do
	DEF^type_def := 4;
	DEFCLASSE^num_classe :=0 ; --XXX to be changed !
        DEF^code := ""; --XXX to be removed, isn't it ?	
end
}
#defclasse{
do
	DEFCLASSE^classe_englobante := DEF^classe;
end
}
#fin{
local classes : TDS<CLASSE>;
	c : CLASSE;
do
	classes := DEF^classe.getSsClasses();
	c := DEFCLASSE^classedef;
	call classes.inserer(c.getName(),c);
	DEF^def_depl := 0; -- TODO deplacement pour les classes
	DEF^code := "";
end
}

-- les types
TYPE-> int #nomtaille ;
#nomtaille {
do
	TYPE^type := new PTYPE("int",1);
end
}

TYPE-> bool #nomtaille ;
#nomtaille {
do
	TYPE^type := new PTYPE("bool",1);
end
}

TYPE-> ident #nomtaille;
#nomtaille {
local typtop : DTYPE;
do
	typtop := TYPE^tdc.chercherGlobalement(ident^txt);
	if (typtop = nil) then
		error(T_03,ident^txt);
	end
	TYPE^type := typtop;
end
}

-- parametres de methodes
PARFS ->  ;
PARFS -> #deb PARF PARFSX ;
#deb{
do
	PARF^empl_param := 0;
	PARFSX^empl_param := 1; --XXX on commence Ã  0, on peut changer..
end
}

PARFSX ->  ;
PARFSX -> #deb virg  PARF  PARFSX ;
#deb{
do
	PARFSX1^empl_param := PARFSX^empl_param + 1;
end
}

PARF ->  TYPE ident #rempl_tdp;
#rempl_tdp{
local param : ATT_PARAM;
do
	param := new ATT_PARAM(TYPE^type, (0-PARF^empl_param), new VISIBILITE(-1), "LB",2);
	call PARF^tdp.inserer(ident^txt, param);
end
}

-- corps de methode et bloc d'instructions
BLOC ->  aco INSTS acf #fin_bloc;
#fin_bloc{
do
	write(BLOC^tds);
	BLOC^code := INSTS^code;
end
}
-- instructions
INSTS ->   #fin;
#fin{
do
	INSTS^code := "";
end
}

INSTS -> INST #passage_depl INSTS  #code ;
#passage_depl {
do
	INSTS1^depl_bloc := INSTS^depl_bloc + INST^new_depl;
end
}
#code{
do
	INSTS^code := INST^code + INSTS1^code;
end
}

-- declaration de variable locale avec ou sans init
INST -> TYPE ident #trtype AFFX pv #ajout;
#trtype{
do
	AFFX^prev_type := TYPE^type;
end
}
#ajout {
local
	le_depl : int;
	var : ATT_PARAM;
do
	le_depl := INST^depl_base + INST^depl_bloc; 
	var := new ATT_PARAM(TYPE^type, le_depl, new VISIBILITE(-1),"LB",1);
	call INST^tds.inserer(ident^txt,var);
	-- on indique a INSTS (au dessus) qu'une affectation a ete faite (cad un nouveau deplacement)
	INST^new_depl := 1;
	-- pour le code
	INST^code := INST^machine.genDecl(var,AFFX^code,ident^txt); --TODO génération de code pour l'affectation + intialisation
end
}

-- instruction expression
INST ->  E pv #pas_de_depl;
#pas_de_depl {
do
	INST^new_depl := 0;
	INST^code := E^code;
end
}

-- bloc d'instructions
INST -> #transtds BLOC #pas_de_depl;
#transtds{
do	
	-- init du depl du bloc
	BLOC^depl_base := INST^depl_base + INST^depl_bloc;  
	BLOC^depl_bloc := 0;

	BLOC^tds := new TDS<ATT_PARAM>(INST^tds);
end
}
#pas_de_depl {
do
	INST^new_depl := 0;
	INST^code := BLOC^code;
end
}

-- conditionnelle
INST -> #transtds si paro E #type parf BLOC SIX #pas_de_depl;
#transtds{
do
	BLOC^tds := new TDS<ATT_PARAM>(INST^tds);
	SIX^tds := new TDS<ATT_PARAM>(INST^tds);
	-- init du depl du bloc
	BLOC^depl_base := INST^depl_base + INST^depl_bloc;  
	BLOC^depl_bloc := 0;
end
}
#type{
do
	if(~E^type.isBooleen()) then
		error(T_00,E^type.getName(),"bool");
	end
end
}
#pas_de_depl {
do
	INST^new_depl := 0;
	INST^code := INST^machine.genIf(E^code,BLOC^code,SIX^code);
end
}

SIX ->  #transtds sinon BLOC #code;
#transtds{
do
	BLOC^tds := new TDS<ATT_PARAM>(SIX^tds);
	-- init du depl du bloc
	BLOC^depl_base := SIX^depl_base + SIX^depl_bloc;  
	BLOC^depl_bloc := 0;
end
}
#code {
do
	SIX^code := BLOC^code;
end
}


SIX -> #code;
#code{
do
	SIX^code := "";
end
}


-- return
INST ->  retour E #type pv #pas_de_depl;
#type {
do
	
end
}
#pas_de_depl {
local
	code_inter: String; 
do
	INST^new_depl := 0;
	INST^code := INST^machine.genReturn(INST^methode, E^code);
end
}

-- tant que
INST -> #transtds tantque paro E #type parf BLOC #pas_de_depl ;
#transtds{
do
	BLOC^tds := new TDS<ATT_PARAM>(INST^tds);

	-- init du depl du bloc
	BLOC^depl_base := INST^depl_base + INST^depl_bloc;  
	BLOC^depl_bloc := 0;
end
}
#type{
do
	if(~E^type.isBooleen()) then
		error(T_00,E^type.getName(),"bool");
	end
end
}
#pas_de_depl {
do
	INST^new_depl := 0;
	INST^code := INST^machine.genWhile(E^code,BLOC^code);
end
}

-- les expressions
E ->  ER #trtype AFFX #type;
#trtype{
do
	AFFX^prev_type := ER^type;
end
}
#type{
do
	E^type := AFFX^type;
	E^code := E^machine.genExpression(ER^code,AFFX^code,ER^estValeur);
end
}

-- affectation
AFFX ->  affect ER #type;
#type{
do
	if(ER^type.heriteDe(AFFX^prev_type)) then
		AFFX^type := AFFX^prev_type;
	else
		error(T_00, ER^type.getName(), AFFX^prev_type.getName());
	end
	AFFX^code := AFFX^machine.genValeur(ER^code,ER^estValeur); --TODO!!
end
}

AFFX -> #type;
#type{
do
	AFFX^type := AFFX^prev_type;
	AFFX^code := ""; --TODO
end
}
-- relation
ER -> ES #trtype ERX #type;
#trtype{
do
	ERX^prev_type := ES^type;
end
}
#type{
do
	ER^type := ERX^type;
	ER^code := ES^code + ERX^code;	
	ER^code := ER^machine.genExprValeur(ES^code, ERX^code,ES^estValeur);
	if (ERX^code.equals("")) then
		ER^estValeur := ES^estValeur;
	else
		ER^estValeur := true;
	end

end
}
ES ->  T #trtype  ESX #type;
#trtype{
do
	ESX^prev_type := T^type;
end
}
#type{
do
	ES^type := ESX^type;
	ES^code := ES^machine.genExprValeur(T^code, ESX^code,T^estValeur);
	if (ESX^code.equals("")) then
		ES^estValeur := T^estValeur;
	else
		ES^estValeur := true;
	end
end
}

ERX ->  OPREL #type0 ES #type1;
#type0{
do
	if(~(OPREL^arg_type=nil) & ~(ERX^prev_type.heriteDe(OPREL^arg_type))) then
		error(T_01, ERX^prev_type.getName(), OPREL^arg_type.getName());
	end
end
}
#type1{
do
	if(OPREL^arg_type=nil) then
		if(~(ERX^prev_type.relieA(ES^type))) then
			error(T_00, ES^type.getName(), ERX^prev_type.getName());
		end
	else
		if(~(ES^type.heriteDe(OPREL^arg_type))) then
			error(T_00, ES^type.getName(), OPREL^arg_type.getName());
		end
	end
	ERX^type := OPREL^type;
	ERX^code := ERX^machine.genExprValeur(ES^code,OPREL^code,"",ES^estValeur);
end
}

ERX -> #type;
#type{
do
	ERX^type := ERX^prev_type;
	ERX^code := "";
end
}
-- OpÃ©rateurs de relation
OPREL -> inf #type;
#type{
do
	OPREL^type := new PTYPE("bool",1);
	OPREL^arg_type := new PTYPE("int",1);
	OPREL^code := OPREL^machine.genInf(); 
end
}
OPREL -> infeg #type;
#type{
do
	OPREL^type := new PTYPE("bool",1);
	OPREL^arg_type := new PTYPE("int",1);	
	OPREL^code := OPREL^machine.genInfEq(); 
end
}
OPREL -> sup #type;
#type{
do
	OPREL^type := new PTYPE("bool",1);
	OPREL^arg_type := new PTYPE("int",1);
	OPREL^code := OPREL^machine.genSup(); 

end
}
OPREL -> supeg #type;
#type{
do
	OPREL^type := new PTYPE("bool",1);
	OPREL^arg_type := new PTYPE("int",1);
	OPREL^code := OPREL^machine.genSupEq(); 

end
}
OPREL -> eg #type;
#type{
do
	OPREL^type := new PTYPE("bool",1);
	OPREL^arg_type := nil;
	OPREL^code := OPREL^machine.genEq(); 
end
}
OPREL -> neg #type;
#type{
do
	OPREL^type := new PTYPE("bool",1);
	OPREL^arg_type := nil;
	OPREL^code := OPREL^machine.genNEq(); 

end
}
-- addition, ...
ESX ->   OPADD #type0 T #type1 ESX #type2;
#type0{
do
	if(~(OPADD^arg_type=nil) & ~(ESX^prev_type.heriteDe(OPADD^arg_type))) then
		error(T_01, ESX^prev_type.getName(), OPADD^arg_type.getName());
	end
end
}
#type1{
do
	if(OPADD^arg_type=nil) then
		if(~(ESX^prev_type.relieA(T^type))) then
			error(T_00, T^type.getName(), ESX^prev_type.getName());
		end
	else
		if(~(T^type.heriteDe(OPADD^arg_type))) then
			error(T_00, T^type.getName(), OPADD^arg_type.getName());
		end
	end
	ESX1^prev_type:=OPADD^type;
end
}
#type2{
do	
	if(OPADD^type = nil) then
		ESX^type := ESX1^type;
	else
		ESX^type := OPADD^type;
	end
	ESX^code := ESX^machine.genExprValeur(T^code,OPADD^code,ESX1^code,T^estValeur);
end
}
ESX ->#type;
#type{
do
	ESX^type := ESX^prev_type;
	ESX^code := "";
	
end
}
OPADD -> plus  #type;
#type{
do
	OPADD^type := new PTYPE("int",1);
	OPADD^arg_type := new PTYPE("int",1);
	OPADD^code := OPADD^machine.genPlus();
end
}
OPADD -> moins  #type;
#type{
do
	OPADD^type := new PTYPE("int",1);
	OPADD^arg_type := new PTYPE("int",1);
	OPADD^code := OPADD^machine.genMoins();
end
}
OPADD -> ou #type;
#type{
do
	OPADD^type := new PTYPE("bool",1);
	OPADD^arg_type := new PTYPE("bool",1);
	OPADD^code := OPADD^machine.genOu();
end
}
T ->  F #trtype TX #type;
#trtype{
do	
	TX^prev_type := F^type;
end
}
#type{
do
	T^type := TX^type;
	T^code := T^machine.genExprValeur(F^code,TX^code,F^estValeur);
	if (TX^code.equals("")) then
		T^estValeur := F^estValeur;
	else
		T^estValeur := true;
	end
end
}
-- multiplication, ...
TX ->   OPMUL #type0 F #type1 TX #type2;
#type0{
do
	if(~(OPMUL^arg_type=nil) & ~(TX^prev_type.heriteDe(OPMUL^arg_type))) then
		error(T_01, TX^prev_type.getName(), OPMUL^arg_type.getName());
	end
end
}
#type1{
do
	if(OPMUL^arg_type=nil) then
		if(~(TX^prev_type.relieA(F^type))) then
			error(T_00, F^type.getName(), TX^prev_type.getName());
		end
	else
		if(~(F^type.heriteDe(OPMUL^arg_type))) then
			error(T_00, F^type.getName(), OPMUL^arg_type.getName());
		end
	end
	TX1^prev_type:=OPMUL^type;
end
}
#type2{
do	
	if(OPMUL^type = nil) then
		TX^type := TX1^type;
	else
		TX^type := OPMUL^type;
	end
	TX^code := TX^machine.genExprValeur(F^code,OPMUL^code,TX1^code,F^estValeur);

end
}
TX -> #type;
#type{
do
	TX^type := TX^prev_type;
	TX^code := "";
end
}
OPMUL -> mult #type;
#type{
do
	OPMUL^type := new PTYPE("int",1);
	OPMUL^arg_type := new PTYPE("int",1);
	OPMUL^code := OPMUL^machine.genMult();
end
}
OPMUL -> div #type;
#type{
do
	OPMUL^type := new PTYPE("int",1);
	OPMUL^arg_type := new PTYPE("int",1);
	OPMUL^code := OPMUL^machine.genDiv();
end
}
OPMUL -> mod #type;
#type{
do
	OPMUL^type := new PTYPE("int",1);
	OPMUL^arg_type := new PTYPE("int",1);
	OPMUL^code := OPMUL^machine.genMod();
end
}
OPMUL -> et #type;
#type{
do
	OPMUL^type := new PTYPE("bool",1);
	OPMUL^arg_type := new PTYPE("bool",1);
	OPMUL^code := OPMUL^machine.genEt();
end
}
-- expressions de base
F -> entier #type  ;
#type{
do
	F^type := new PTYPE("int",1);
	F^code := F^machine.genInt(entier^txt);
	F^estValeur := true;
end
}
F -> vrai #type ;
#type{
do
	F^type := new PTYPE("bool",1);
	F^code := F^machine.genTrue();
	F^estValeur := true;
end
}
F -> faux #type ;
#type{
do
	F^type := new PTYPE("bool",1);
	F^code := F^machine.genFalse();
	F^estValeur := true;
end
}
-- unaire
F ->  OPUN F #type2;
#type2{
do
	if(~(OPUN^arg_type=nil) & ~(F1^type.heriteDe(OPUN^arg_type))) then
		error(T_00, F1^type.getName(), OPUN^arg_type.getName());
	end
	if(OPUN^type = nil) then	
		F^type := F1^type;
	else
		F^type := OPUN^type;
	end
	F^code :=F^machine.genExprValeur(F1^code,OPUN^code,F1^estValeur);
	F^estValeur := true;
end
}
OPUN -> plus #type;
#type{
do
	OPUN^type := new PTYPE("int",1);
	OPUN^arg_type := new PTYPE("int",1);
	OPUN^code := ""; --XXX not sure, certainly :)
end
}
OPUN -> moins #type;
#type{
do
	OPUN^type := new PTYPE("int",1);
	OPUN^arg_type := new PTYPE("int",1);
	OPUN^code := OPUN^machine.genMoinsInt();
end
}
OPUN -> non #type;
#type{
do
	OPUN^type := new PTYPE("bool",1);
	OPUN^arg_type := new PTYPE("bool",1);
	OPUN^code := OPUN^machine.genNegation();
end
}
-- null
F -> nil #type;
#type{
do
	F^type := new PTYPE("null",1);
	F^code := F^machine.genNull();
	F^estValeur := true;
end
}
F ->  paro E parf #type;
#type{
do
	F^type := E^type;
	F^code := E^code;
	F^estValeur := true;
end
}
-- new
F -> #debut nouveau TYPE paro ARGS parf #type;
global arguments : List<DTYPE>;
#debut{
do
	arguments := new Vector<DTYPE>();
	ARGS^args := arguments;
end
}
#type{
local
	classe : CLASSE;
	constr : CONSTRUCTEUR;
do
	classe := F^tdc.chercherGlobalement(TYPE^type.getName());
	constr := classe.getConstructeur(arguments);
	if (constr = nil) then
		error(T_09,classe.getName()+arguments);
	end
	F^type := TYPE^type;
	F^code := F^machine.genAppelConstr(constr,ARGS^code,classe);
	F^estValeur := true; ---XXXX
end
}
F ->  ident #type0 Q #type1;
#type0{
local
	var : ATT_PARAM;
do
	var := F^tds.chercherGlobalement(ident^txt);
	Q^ident := ident^txt;
	Q^prev_type := nil;
	Q^hcode := "";
	Q^hCodeEstValeur := true;
end
}
#type1{
do
	F^type := Q^type;
	F^code := Q^code;
	F^estValeur := Q^estValeur;

end
}
-- Q = qualificateur de variable
Q -> #type;
#type{
local
	classe : CLASSE;
	attributs : TDS<ATT_PARAM>;
	var : ATT_PARAM;
do
	Q^code := "";
	if(Q^ident = nil) then 	--prÃ©cÃ©dent = mÃ©thode,
				-- type de retour dans prev_type
		Q^type := Q^prev_type;
		Q^code := Q^hcode;
		Q^estValeur := true;
	else  --prÃ©cÃ©dent = attribut
		Q^estValeur := false;
		----- vÃ©rification prÃ©cÃ©dent -----
		if (Q^prev_type = nil) then -- premiÃ¨re (et derniÃ¨re) variable d'acces
			var := Q^tds.chercherGlobalement(Q^ident);
			if(var = nil) then
				error(T_02,Q^ident);
			end
			Q^code := Q^machine.genAccesAttVarLoc(var,Q^methode, Q^ident);	
		else
			if (Q^prev_type.isPrimitif()) then
				error(T_04,Q^ident,Q^prev_type.getName());
			end
			classe := Q^prev_type.getClasse();
			attributs := classe.getAttributs();
			var := attributs.chercherLocalement(Q^ident);
			if(var = nil) then
				error(T_05,Q^ident,classe.getName());
			end
			Q^code := Q^machine.genValeur(Q^hcode, Q^hCodeEstValeur) + Q^machine.genAccesAttribut(var, Q^ident); 
		end
		----- transmission type ----- 
		Q^type := var.getType();
	end
end
}
-- acces attribut ou methode
Q -> pt ident #type0 Q #type1;
#type0{
local
	classe : CLASSE;
	attributs : TDS<ATT_PARAM>;
	var : ATT_PARAM;
do
	if(Q^ident = nil) then 	--prÃ©cÃ©dent = mÃ©thode,
				-- type de retour dans prev_type
		Q1^prev_type := Q^prev_type; --type de retour de la mÃ©thode
		Q1^ident := ident^txt;
		Q1^hcode := Q^hcode;
		Q1^hCodeEstValeur := Q^hCodeEstValeur;
	else  --prÃ©cÃ©dent = attribut
		----- vÃ©rification prÃ©cÃ©dent -----
		if (Q^prev_type = nil) then -- premiÃ¨re variable d'acces (a si a.*.*.*)
			var := Q^tds.chercherGlobalement(Q^ident);
			if(var = nil) then
				error(T_02,Q^ident);
			end
			Q1^hcode := Q^machine.genAccesAttVarLoc(var, Q^methode, Q^ident);  
			Q1^hCodeEstValeur := false;
		else
			if (Q^prev_type.isPrimitif()) then
				error(T_04,Q^ident,Q^prev_type.getName());
			end
			classe := Q^prev_type.getClasse();
			attributs := classe.getAttributs();
			var := attributs.chercherLocalement(Q^ident);
			if(var = nil) then
				error(T_05,Q^ident,classe.getName());
			end
			Q1^hcode := Q^machine.genValeur(Q^hcode, Q^hCodeEstValeur) + Q^machine.genAccesAttribut(var, Q^ident);
			Q1^hCodeEstValeur := false;
		end
		----- transmission suivant ------
		Q1^prev_type := var.getType();
		Q1^ident := ident^txt;
	end
end
}
#type1{
do
	Q^type := Q1^type;
	Q^code := Q1^code;
	Q^estValeur := Q1^estValeur;
end
}
-- arguments d'appel de methode
Q -> #debut paro ARGS parf #type0 Q #type1 ;
global arguments : List<DTYPE>;
#debut{ 
do
	arguments := new Vector<DTYPE>();
	ARGS^args := arguments;
end
}
#type0{
local
	classe : CLASSE;
	meths : TDS<METHODE>;
	meth : METHODE;
	prevCode : String;
	var : ATT_PARAM;
do
	Q^code :="";
	if(Q^ident = nil) then --precedent = methode
		error(T_07);
	else  --precedent = nom de la Methode
		if (Q^prev_type = nil) then -- premiere variable d'acces (m si m().*.*.*)
			classe := Q^classe;
			--write "top :"+Q^ident;
			prevCode := Q^machine.genAccesObjetCourant(Q^methode);  			
		else
			if (Q^prev_type.isPrimitif()) then
				error(T_04,Q^ident,Q^prev_type.getName());
			end
			-- TODO surcharge
			classe := Q^prev_type.getClasse();
			-- TODO verif meth.getSignature() compatible avec arguments.
			prevCode := Q^machine.genValeur(Q^hcode, Q^hCodeEstValeur);
		end
		meth := classe.getMethode(Q^ident, arguments, true);
		if (meth = nil) then
			error(T_06,Q^ident+arguments);
		end
		Q1^prev_type := meth.getReturnType();
 		Q1^ident := nil;
		Q1^hcode := prevCode + Q^machine.genAppelMethode(meth,ARGS^code,Q^tdc);
		Q1^hCodeEstValeur := true;	
	end
end
}
#type1{
do
	Q^type := Q1^type;
	Q^code := Q1^code;
	Q^estValeur := Q1^estValeur;
end
}
ARGS -> E #rempl_args ARGSX #code;
#rempl_args{
do
	call ARGS^args.add(E^type);
--	ARGS^args.size();
end
}
#code {
do
	ARGS^code := ARGSX^code + E^code;
end
}
ARGS -> #code;
#code{
do
	ARGS^code := "";
end
}

ARGSX -> virg E #rempl_args ARGSX #code;
#rempl_args{
do
	call ARGSX^args.add(E^type);
end
}
#code{
do
	ARGSX^code := ARGSX1^code+ E^code;
end
}
ARGSX -> #code;
#code{
do
	ARGSX^code := "";
end
}

-- messages obligatoires
S_00, "Symbole inattendu : '^1' au lieu de '^2'." ,2 ;
S_01, "Fin de source attendue pres de '^1'.",1;
S_02, "Symbole inattendu '^1'." ,1 ;
-- messages specifiques a partir d'ici
T_00, "Tu es sur que tu comprends ce que tu fais ?\n\t-> Type inattendu : '^1' au lieu de '^2'.",2;
T_01, "Ce que tu ecris ne veut rien dire... ?\n\t-> Operateur inattendu : argument possible '^2' non compatible avec '^1'.",2;
T_02, "Tout ce que je sais, c'est que je ne sais rien (Socrate).\n\t-> Variable '^1' non precedement declaree.",1;
T_03, "T nul !\n\t-> La classe '^1' est non precedement definie",1;
T_04, "Pffff... Fais attention !!\n\t->Acces a l'attribut '^1' sur le type primitif '^2'.",2;
T_05, "Allez !! Encore une gourde !\n\t->Acces a l'attribut '^1' inexistant dans la classe '^2'.",2;
T_06, "Meeeeuh !! Ca marche pas comme ca !\n\t->Acces a la methode '^1' non precedement declaree",1;
T_07, "Euhh... Alors la, si tu l'as pas fait expres...",0;
T_08, "La methode '^1' a deja ete definie precedement !",1;
T_09, "Le constructeur '^1' est non precedement definie !",1;
T_10, "Le constructeur '^1' a deja ete definie precedement !",1;
end

